package com.asr.plugin_asr

import android.Manifest
import android.content.Context
import androidx.annotation.RequiresPermission
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.asr.plugin_asr.bean.FlowTTSBean
import com.asr.plugin_asr.bean.InitBean
import com.asr.plugin_asr.ktx.log
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/** PluginAsrPlugin */
class PluginAsrPlugin: FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private lateinit var channel : MethodChannel
  private lateinit var context: Context

  override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "plugin_asr")
    channel.setMethodCallHandler(this)
    context = flutterPluginBinding.applicationContext
    ASRSdk.setContext(context)
  }

  @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
  override fun onMethodCall(call: MethodCall, result: Result) {
    if (!ASRSdk.isNetworkConnected() && call.method != "init") {
      result.error("CALL_FAILED", "没有网络，无法调用此插件", null)
      return
    }
    when (call.method) {
      // 初始化ASR SDK，必须首先调用此方法
      "init" -> {
        init(call, result)
      }
      // 开始语音识别监听
      "startAsrListener" -> {
        startAsrListener(call, result)
      }
      // 停止语音识别监听
      "stopAsrListener" -> {
        stopAsrListener(call, result)
      }
      // 开始在线语音合成
      "startOnlineTTS" -> {
        startOnlineTTS(call, result)
      }
      // 停止在线语音合成
      "stopOnlineTTS" -> {
        stopOnlineTTS(call, result)
      }
      // 开始拟人语音合成
      "startPersonTTS" -> {
        startPersonTTS(call, result)
      }
      // 开始流式拟人语音合成
      "startFlowPersonTTS" -> {
        startFlowPersonTTS(call, result)
      }
      // 停止拟人语音合成
      "stopPersonTTS" -> {
        stopPersonTTS(call, result)
      }
      // 未识别的方法调用
      else -> {
        result.notImplemented()
      }
    }
  }


  /**
   * 处理"init"方法调用，初始化ASR SDK。
   *
   * @param call 包含初始化参数的MethodCall对象。
   * @param result 用于向Flutter返回初始化结果的结果对象。
   */
  private fun init(call: MethodCall, result: Result) {
    try {
      // 解析传入的JSON参数为InitBean对象
      val argBean = JSON.parseObject(call.arguments.toString(), InitBean::class.java)

      // 检查必要参数是否为空
      if (argBean.appId.isNullOrEmpty() || argBean.apiKey.isNullOrEmpty() || argBean.apiSecret.isNullOrEmpty()) {
        result.error("INVALID_ARGUMENTS", "缺少必填参数：appId、apiKey 或 apiSecret", null)
        return
      }

      // 调用ASRSdk的初始化方法
      val ret = ASRSdk.init(argBean.appId, argBean.apiKey, argBean.apiSecret)

      // 返回初始化结果
      result.success(ret)
    } catch (e: Exception) {
      // 捕获并返回异常信息
      result.error("INIT_FAILED", "ASR SDK 初始化失败：原因 - ${e.message}", null)
    }
  }


  /**
   * 处理"startAsrListener"方法调用，开始语音识别监听。
   *
   * @param call 包含回调方法名的MethodCall对象。
   * @param result 用于向Flutter返回启动结果的结果对象。
   */
  private fun startAsrListener(call: MethodCall, result: Result) {
    try {
      val language = call.arguments.toString()
      val callbackMethodName = "asrListenerProcess"
      // 调用ASRSdk的开始语音识别监听方法，并设置结果回调
      val ret = ASRSdk.startAsrListener (
        language,
        { res ->
          // 在主线程中通过MethodChannel将结果发送回Flutter
          CoroutineScope(Dispatchers.Main).launch {
            try {
              result.success(res)
            } catch (e: Exception) {
              // 捕获并记录发送结果时的异常
              e.printStackTrace()
            }
          }
        },
        { res ->
          CoroutineScope(Dispatchers.Main).launch {
            try {
              channel.invokeMethod(callbackMethodName, res)
            } catch (e: Exception) {
              // 捕获并记录发送结果时的异常
              e.printStackTrace()
            }
          }
        }
      )
      if (ret != 0) {
        result.success("")
      }
      // 返回启动结果
    } catch (e: Exception) {
      // 捕获并返回异常信息
      result.error("START_ASR_FAILED", "ASR 开始语音识别监听失败：原因 - ${e.message}", null)
    }
  }

  /**
   * 处理"stopAsrListener"方法调用，停止语音识别监听。
   *
   * @param call 不使用，可为null。
   * @param result 用于向Flutter返回停止结果的结果对象。
   */
  private fun stopAsrListener(call: MethodCall, result: Result) {
    try {
      // 调用ASRSdk的停止语音识别监听方法
      ASRSdk.stopAsrListener()

      // 返回停止结果
      result.success(0)
    } catch (e: Exception) {
      // 捕获并返回异常信息
      result.error("STOP_ASR_FAILED", "ASR 停止语音识别监听失败：原因 - ${e.message}", null)
    }
  }

  /**
   * 处理"startOnlineTTS"方法调用，开始在线语音合成。
   *
   * @param call 包含待合成文本的MethodCall对象。
   * @param result 用于向Flutter返回合成结果的结果对象。
   */
  private fun startOnlineTTS(call: MethodCall, result: Result) {
    try {
      // 从参数中获取待合成的文本
      val text = call.arguments.toString()

      // 检查文本是否为空
      if (text.isEmpty()) {
        result.error("EMPTY_TEXT", "语音合成文本不能为空", null)
        return
      }

      // 调用ASRSdk的开始在线语音合成方法
      val ret = ASRSdk.startOnlineTTS(text)

      // 返回合成结果
      result.success(ret)
    } catch (e: Exception) {
      // 捕获并返回异常信息
      result.error("START_TTS_FAILED", "语音合成失败：原因: ${e.message}", null)
    }
  }

  /**
   * 处理"stopOnlineTTS"方法调用，结束在线语音合成。
   *
   * @param call 包含待合成文本的MethodCall对象。
   * @param result 用于向Flutter返回合成结果的结果对象。
   */
  private fun stopOnlineTTS(call: MethodCall, result: Result) {
    val ret = ASRSdk.stopOnlineTTS()
    result.success(ret)
  }

  /**
  * 处理"startPersonTTS"方法调用，开始拟人语音合成。
  *
  * @param call 包含待合成文本的MethodCall对象。
  * @param result 用于向Flutter返回合成结果的结果对象。
  */
  private fun startPersonTTS(call: MethodCall, result: Result) {
    try {
      // 从参数中获取待合成的文本
      val text = call.arguments.toString()

      // 检查文本是否为空
      if (text.isEmpty()) {
        result.error("EMPTY_TEXT", "语音合成文本不能为空", null)
        return
      }

      // 调用ASRSdk的开始在线语音合成方法
      val ret = ASRSdk.startPersonTTS(text) {
        // 播放结束
        result.success(it)
      }
      if (ret != 0) {
        result.success(ret);
      }

    } catch (e: Exception) {
      // 捕获并返回异常信息
      result.error("START_TTS_FAILED", "语音合成失败：原因: ${e.message}", null)
    }
  }

  /**
   * 处理"startFlowPersonTTS"方法调用，开始流式拟人语音合成。
   *
   * @param call 包含待合成文本的MethodCall对象。
   * @param result 用于向Flutter返回合成结果的结果对象。
   */
  private fun startFlowPersonTTS(call: MethodCall, result: Result) {
    try {
      // 从参数中获取待合成的文本
      val argBean = JSON.parseObject(call.arguments.toString(), FlowTTSBean::class.java)
      val text = argBean.text
      val status = argBean.status
      // 检查文本是否为空
      if (text.isEmpty()) {
        result.error("EMPTY_TEXT", "语音合成文本不能为空", null)
        return
      }
      var isResultBack = false
      // 调用ASRSdk的开始在线语音合成方法
      val ret = ASRSdk.startFlowPersonTTS(text, status) {
        // 播放结束
        if (isResultBack == false) {
          isResultBack = true
          result.success(it)
        }
      }
      if(ret != 0) {
        isResultBack = true
        result.success(ret)
        return;
      }
      // 不等于2的状态都直接返回，等于2的状态等待语音播放完成
      if (status != 2) {
        // 返回合成结果
        isResultBack = true
        result.success(ret)
      }
    } catch (e: Exception) {
      // 捕获并返回异常信息
      result.error("START_TTS_FAILED", "语音合成失败：原因: ${e.message}", null)
    }
  }

  /**
   * 处理"stopPersonTTS"方法调用，结束在线语音合成。
   *
   * @param call 包含待合成文本的MethodCall对象。
   * @param result 用于向Flutter返回合成结果的结果对象。
   */
  private fun stopPersonTTS(call: MethodCall, result: Result) {
    val ret = ASRSdk.stopPersonTTS()
    result.success(ret)
  }


  override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }

}
